import { defineStore } from 'pinia';
import { MESSAGE_TYPE, MESSAGE_STATUS, AI_ASSISTANT } from "@/utils/im/enums.js"
import useFriendStore from './friendStore.js';
import useGroupStore from './groupStore.js';
import useUserStore from './userStore.js';
import localForage from 'localforage';

/**
 * 优化1(冷热消息分区):
 * 热消息：登录后的消息
 * 冷消息: 登录前的消息
 * 每个会话的冷热消息分别用一个key进行存储，当有新的消息时，只更新热消息key，冷消息key保持不变
 * 由于热消息数量不会很大，所以localForage.setItem耗时很低，可以防止消息过多时出现卡顿的情况
 *
 * 优化2(延迟渲染):
 * 拉取消息时，如果直接用state.chats接收，页面就开始渲染，一边渲染页面一边大量接消息会导致很严重的卡顿
 * 为了加速拉取离线消息效率，拉取时消息暂时存储到cacheChats,等待所有离线消息拉取完成后，再统一放至state中进行渲染
 * 
 * 优化3(pinia代替vuex)
 * 实测pinia的远超vuex,且语法更简洁清晰
 * 
 * */

let cacheChats = [];

export default defineStore('chatStore', {
	state: () => {
		return {
			activeChat: null,
			privateMsgMaxId: 0,
			groupMsgMaxId: 0,
			loadingPrivateMsg: false,
			loadingGroupMsg: false,
			chats: []
		}
	},
	actions: {
		initChats(chatsData) {
			this.chats = [];
			this.privateMsgMaxId = chatsData.privateMsgMaxId || 0;
			this.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
			cacheChats = chatsData.chats || [];
			// 防止图片一直处在加载中状态
			cacheChats.forEach((chat) => {
				chat.messages.forEach((msg) => {
					if (msg.loadStatus == "loading") {
						msg.loadStatus = "fail"
					}
				})
			})
		},
		/**
		 * 打开聊天会话
		 * @param {Object} chatInfo - 聊天信息
		 * @param {boolean} updateTime - 是否更新会话时间，默认false（点击发消息按钮不更新时间）
		 */
		openChat(chatInfo, updateTime = false) {
			let chats = this.findChats()
			let chat = null;
			for (let idx in chats) {
				if (chats[idx].type == chatInfo.type &&
					chats[idx].targetId === chatInfo.targetId) {
					chat = chats[idx];
					// 将会话移到顶部，但不更新时间（保持最近聊天记录的时间）
					this.moveTop(idx, updateTime)
					break;
				}
			}
			// 创建会话
			if (chat == null) {
				// 检查是否是删除后重新打开的会话
				const wasDeleted = this.wasChatDeleted(chatInfo.type, chatInfo.targetId);

				chat = {
					targetId: chatInfo.targetId,
					type: chatInfo.type,
					showName: chatInfo.showName,
					headImage: chatInfo.headImage,
					isDnd: chatInfo.isDnd,
					lastContent: wasDeleted ? "重新开始聊天" : "",
					// 如果是删除后重新打开，设置当前时间；否则保持为0等有消息时再设置
					lastSendTime: wasDeleted ? new Date().getTime() : 0,
					unreadCount: 0,
					hotMinIdx: 0,
					messages: [],
					atMe: false,
					atAll: false,
					stored: false,
					delete: false
				};
				chats.unshift(chat);
			}
		},
		setActiveChat(idx) {
			let chats = this.findChats();
			this.activeChat = chats[idx];
		},
		resetUnreadCount(chatInfo) {
			let chats = this.findChats();
			for (let idx in chats) {
				if (chats[idx].type == chatInfo.type &&
					chats[idx].targetId == chatInfo.targetId) {
					chats[idx].unreadCount = 0;
					chats[idx].atMe = false;
					chats[idx].atAll = false;
					chats[idx].stored = false;
					this.saveToStorage();
					break;
				}
			}
		},
		readedMessage(pos) {
			let chat = this.findChatByFriend(pos.friendId);
			if (!chat) return;
			chat.messages.forEach((m) => {
				if (m.id && m.selfSend && m.status < MESSAGE_STATUS.RECALL) {
					// pos.maxId为空表示整个会话已读
					if (!pos.maxId || m.id <= pos.maxId) {
						m.status = MESSAGE_STATUS.READED
						chat.stored = false;
					}
				}
			})
			this.saveToStorage();
		},
		removeChat(idx) {
			let chats = this.findChats();
			if (chats[idx] == this.activeChat) {
				this.activeChat = null;
			}
			// 记录删除的会话信息，用于后续重新打开时的时间处理
			const deletedChat = chats[idx];
			this.markChatAsDeleted(deletedChat.type, deletedChat.targetId);

			chats[idx].delete = true;
			chats[idx].stored = false;
			this.saveToStorage();
		},

		// 标记会话为已删除（用于时间处理）
		markChatAsDeleted(type, targetId) {
			const key = `deleted_chat_${type}_${targetId}`;
			localStorage.setItem(key, Date.now().toString());
		},

		// 检查会话是否曾被删除
		wasChatDeleted(type, targetId) {
			const key = `deleted_chat_${type}_${targetId}`;
			const deletedTime = localStorage.getItem(key);
			if (deletedTime) {
				// 清除标记，避免重复使用
				localStorage.removeItem(key);
				return true;
			}
			return false;
		},
		removePrivateChat(friendId) {
			let chats = this.findChats();
			for (let idx in chats) {
				if (chats[idx].type == 'PRIVATE' &&
					chats[idx].targetId === friendId) {
					this.removeChat(idx);
					break;
				}
			}
		},
		removeGroupChat(groupId) {
			let chats = this.findChats();
			for (let idx in chats) {
				if (chats[idx].type == 'GROUP' &&
					chats[idx].targetId === groupId) {
					this.removeChat(idx);
					break;
				}
			}
		},
		/**
		 * 将会话移动到顶部
		 * @param {number} idx - 会话索引
		 * @param {boolean} updateTime - 是否更新会话时间，默认true（发送消息时更新，点击切换时不更新）
		 */
		moveTop(idx, updateTime = true) {
			// 加载中不移动，很耗性能
			if (this.isLoading()) {
				return;
			}
			if (idx > 0) {
				let chats = this.findChats();
				let chat = chats[idx];
				chats.splice(idx, 1);
				chats.unshift(chat);
				// 只有在明确需要更新时间时才更新（比如发送消息时）
				// 点击"发消息"按钮跳转聊天时不更新，保持原有的最近聊天记录时间
				if (updateTime) {
					chat.lastSendTime = new Date().getTime();
				}
				chat.stored = false;
				this.saveToStorage();
			}
		},
		insertMessage(msgInfo, chatInfo) {
			let time = new Date().getTime()
			let type = chatInfo.type;
			// 记录消息的最大id
			if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) {
				this.privateMsgMaxId = msgInfo.id;
			}
			if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) {
				this.groupMsgMaxId = msgInfo.id;
			}
			// 如果是已存在消息，则覆盖旧的消息数据
			let chat = this.findChat(chatInfo);
			let message = this.findMessage(chat, msgInfo);
			if (message) {
				Object.assign(message, msgInfo);
				chat.stored = false;
				this.saveToStorage();
				return;
			}
			// 插入新的数据
			if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
				chat.lastContent = "[图片]";
			} else if (msgInfo.type == MESSAGE_TYPE.FILE) {
				chat.lastContent = "[文件]";
			} else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
				chat.lastContent = "[语音]";
			} else if (msgInfo.type == MESSAGE_TYPE.MIXED) {
				// 混合消息显示内容，不包含用户名称
				try {
					const mixedData = JSON.parse(msgInfo.content);
					if (mixedData.items && Array.isArray(mixedData.items)) {
						let displayParts = [];
						let hasImage = false;

						// 遍历所有项目，收集文字内容和图片标识
						mixedData.items.forEach(item => {
							if (item.type === 'text' && item.content) {
								// 去除HTML标签、表情符号和换行符，只保留纯文本
								const cleanText = item.content
									.replace(/<[^>]*>/g, '')
									.replace(/#[^;]+;/g, '')
									.replace(/\n/g, ' ')
									.trim();
								if (cleanText) {
									displayParts.push(cleanText);
								}
							} else if (item.type === 'image') {
								hasImage = true;
							}
						});

						// 组合显示内容
						let displayText = displayParts.join(' ');
						if (hasImage && displayText) {
							// 有图片和文字：显示 [图片]文字内容
							displayText = displayText.length > 20 ? displayText.substring(0, 20) + '...' : displayText;
							chat.lastContent = "[图片]" + displayText;
						} else if (hasImage) {
							// 只有图片：显示 [图片]
							chat.lastContent = "[图片]";
						} else if (displayText) {
							// 只有文字：显示文字内容
							displayText = displayText.length > 30 ? displayText.substring(0, 30) + '...' : displayText;
							chat.lastContent = displayText;
						} else {
							chat.lastContent = "[图片+文字]";
						}
					} else {
						chat.lastContent = "[图片+文字]";
					}
				} catch (e) {
					chat.lastContent = "[图片+文字]";
				}
			} else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) {
				chat.lastContent = "[语音通话]";
			} else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) {
				chat.lastContent = "[视频通话]";
			} else if (msgInfo.type == MESSAGE_TYPE.TEXT ||
				msgInfo.type == MESSAGE_TYPE.RECALL ||
				msgInfo.type == MESSAGE_TYPE.TIP_TEXT) {
				// 特殊处理AI消息的会话列表显示
				if (msgInfo.sendId === AI_ASSISTANT.XIAO_ASSISTANT_ID || msgInfo.isAIMessage) { // AI助手消息
					chat.lastContent = this.extractAIResponseForChat(msgInfo.content, chat);
					// AI消息的昵称显示规则：私聊不显示昵称，群聊显示"小K"
					chat.sendNickName = chat.type === 'GROUP' ? msgInfo.sendNickName : '';
				} else {
					// 确保content是字符串类型
					chat.lastContent = typeof msgInfo.content === 'string' ? msgInfo.content : String(msgInfo.content || '');
					chat.sendNickName = msgInfo.sendNickName;
				}
			}
			chat.lastSendTime = msgInfo.sendTime;
			// 未读加1
			if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED &&
				msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
				chat.unreadCount++;
			}
			// 是否有人@我
			if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds &&
				msgInfo.status != MESSAGE_STATUS.READED) {
				let userStore = useUserStore();
				let userId = userStore.userInfo.id;
				if (msgInfo.atUserIds.indexOf(userId) >= 0) {
					chat.atMe = true;
				}
				if (msgInfo.atUserIds.indexOf(-1) >= 0) {
					chat.atAll = true;
				}
			}
			// 间隔大于10分钟插入时间显示
			if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) {
				chat.messages.push({
					sendTime: msgInfo.sendTime,
					type: MESSAGE_TYPE.TIP_TIME,
				});
				chat.lastTimeTip = msgInfo.sendTime;
			}
			// 根据id顺序插入，防止消息乱序
			let insertPos = chat.messages.length;
			// 防止 图片、文件 在发送方 显示 在顶端  因为还没存库，id=0
			if (msgInfo.id && msgInfo.id > 0) {
				for (let idx in chat.messages) {
					if (chat.messages[idx].id && msgInfo.id < chat.messages[idx].id) {
						insertPos = idx;
						console.log(`消息出现乱序,位置:${chat.messages.length},修正至:${insertPos}`);
						break;
					}
				}
			}
			chat.messages.splice(insertPos, 0, msgInfo);
			chat.stored = false;
			this.saveToStorage();
			console.log("耗时:", new Date().getTime() - time)
		},
		updateMessage(msgInfo, chatInfo) {
			// 获取对方id或群id
			let chat = this.findChat(chatInfo);
			let message = this.findMessage(chat, msgInfo);
			if (message) {
				// 属性拷贝
				Object.assign(message, msgInfo);

				// 如果是AI消息且流式传输完成，更新会话列表的最后消息
				if ((msgInfo.sendId === AI_ASSISTANT.XIAO_ASSISTANT_ID || msgInfo.isAIMessage) &&
					msgInfo.streamType === 'complete' && !msgInfo.isStreaming) {
					// 特殊处理AI消息的会话列表显示
					chat.lastContent = this.extractAIResponseForChat(msgInfo.content, chat);
					chat.lastSendTime = msgInfo.sendTime;
					// AI消息的昵称显示规则：私聊不显示昵称，群聊显示"小K"
					chat.sendNickName = chat.type === 'GROUP' ? msgInfo.sendNickName : '';
				}

				chat.stored = false;
				this.saveToStorage();
			}
		},
		deleteMessage(msgInfo, chatInfo) {
			let chat = this.findChat(chatInfo);
			let isColdMessage = false;
			for (let idx in chat.messages) {
				// 已经发送成功的，根据id删除
				if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
					chat.messages.splice(idx, 1);
					isColdMessage = idx < chat.hotMinIdx;
					break;
				}
				// 正在发送中的消息可能没有id，只有临时id
				if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
					chat.messages.splice(idx, 1);
					isColdMessage = idx < chat.hotMinIdx;
					break;
				}
			}
			chat.stored = false;
			this.saveToStorage(isColdMessage);
		},
		recallMessage(msgInfo, chatInfo) {
			let chat = this.findChat(chatInfo);
			if (!chat) return;
			let isColdMessage = false;
			// 要撤回的消息id
			let id = msgInfo.content;
			let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName;
			for (let idx in chat.messages) {
				let m = chat.messages[idx];
				if (m.id && m.id == id) {
					// 改造成一条提示消息
					m.status = MESSAGE_STATUS.RECALL;
					m.content = name + "撤回了一条消息";
					m.type = MESSAGE_TYPE.TIP_TEXT
					// 会话列表
					chat.lastContent = m.content;
					chat.lastSendTime = msgInfo.sendTime;
					chat.sendNickName = '';
					if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) {
						chat.unreadCount++;
					}
					isColdMessage = idx < chat.hotMinIdx;
				}
				// 被引用的消息也要撤回
				if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
					m.quoteMessage.content = "引用内容已撤回";
					m.quoteMessage.status = MESSAGE_STATUS.RECALL;
					m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT
				}
			}
			chat.stored = false;
			this.saveToStorage(isColdMessage);
		},
		updateChatFromFriend(friend) {
			let chat = this.findChatByFriend(friend.id);
			// 更新会话中的群名和头像
			if (chat && (chat.headImage != friend.headImage ||
				chat.showName != friend.nickName)) {
				chat.headImage = friend.headImage;
				chat.showName = friend.nickName;
				chat.stored = false;
				this.saveToStorage()
			}
		},
		updateChatFromUser(user) {
			let chat = this.findChatByFriend(user.id);
			// 更新会话中的昵称和头像
			if (chat && (chat.headImage != user.headImageThumb ||
				chat.showName != user.nickName)) {
				chat.headImage = user.headImageThumb;
				chat.showName = user.nickName;
				chat.stored = false;
				this.saveToStorage();
			}
		},
		updateChatFromGroup(group) {
			let chat = this.findChatByGroup(group.id);
			// 优先使用headImage，如果没有则使用headImageThumb
			const groupHeadImage = group.headImage || group.headImageThumb || '';
			if (chat && (chat.headImage != groupHeadImage ||
				chat.showName != group.showGroupName)) {
				// 更新会话中的群名称和头像
				chat.headImage = groupHeadImage;
				chat.showName = group.showGroupName;
				chat.stored = false;
				this.saveToStorage()
			}
		},
		setLoadingPrivateMsg(loading) {
			this.loadingPrivateMsg = loading;
			if (!this.isLoading()) {
				this.refreshChats();
			}
		},
		setLoadingGroupMsg(loading) {
			this.loadingGroupMsg = loading;
			if (!this.isLoading()) {
				this.refreshChats();
			}
		},
		setDnd(chatInfo, isDnd) {
			let chat = this.findChat(chatInfo);
			if (chat) {
				chat.isDnd = isDnd;
			}
		},
		refreshChats() {
			if (!cacheChats) return;
			// 刷新免打扰状态
			const friendStore = useFriendStore();
			const groupStore = useGroupStore();
			cacheChats.forEach(chat => {
				if (chat.type == 'PRIVATE') {
					let friend = friendStore.findFriend(chat.targetId);
					if (friend) {
						chat.isDnd = friend.isDnd
					}
				} else if (chat.type == 'GROUP') {
					let group = groupStore.findGroup(chat.targetId);
					if (group) {
						chat.isDnd = group.isDnd
					}
				}
			})
			// 排序
			cacheChats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime);
			// 记录热数据索引位置
			cacheChats.forEach(chat => chat.hotMinIdx = chat.messages.length);
			// 将消息一次性装载回来
			this.chats = cacheChats;
			// 清空缓存
			cacheChats = null;
			// 持久化消息
			this.saveToStorage(true);
		},
		saveToStorage(withColdMessage) {
			// 加载中不保存，防止卡顿
			if (this.isLoading()) {
				return;
			}
			let userStore = useUserStore();
			let userId = userStore.userInfo.id;
			let key = "chats-" + userId;
			let chatKeys = [];
			// 按会话为单位存储，
			this.chats.forEach((chat) => {
				// 只存储有改动的会话
				let chatKey = `${key}-${chat.type}-${chat.targetId}`
				if (!chat.stored) {
					if (chat.delete) {
						localForage.removeItem(chatKey);
					} else {
						// 存储冷数据
						if (withColdMessage) {
							let coldChat = Object.assign({}, chat);
							coldChat.messages = chat.messages.slice(0, chat.hotMinIdx);
							localForage.setItem(chatKey, coldChat)
						}
						// 存储热消息
						let hotKey = chatKey + '-hot';
						let hotChat = Object.assign({}, chat);
						hotChat.messages = chat.messages.slice(chat.hotMinIdx)
						localForage.setItem(hotKey, hotChat)
					}
					chat.stored = true;
				}
				if (!chat.delete) {
					chatKeys.push(chatKey);
				}
			})
			// 会话核心信息
			let chatsData = {
				privateMsgMaxId: this.privateMsgMaxId,
				groupMsgMaxId: this.groupMsgMaxId,
				chatKeys: chatKeys
			}
			localForage.setItem(key, chatsData)
			// 清理已删除的会话
			this.chats = this.chats.filter(chat => !chat.delete)
		},
		clear() {
			cacheChats = []
			this.chats = [];
			this.activeChat = null;
		},
		loadChat() {
			return new Promise((resolve, reject) => {
				let userStore = useUserStore();
				let userId = userStore.userInfo.id;
				let key = "chats-" + userId;
				localForage.getItem(key).then((chatsData) => {
					if (!chatsData) {
						resolve();
					} else if (chatsData.chatKeys) {
						const promises = [];
						chatsData.chatKeys.forEach(key => {
							promises.push(localForage.getItem(key))
							promises.push(localForage.getItem(key + "-hot"))
						})
						Promise.all(promises).then(chats => {
							chatsData.chats = [];
							// 偶数下标为冷消息，奇数下标为热消息
							for (let i = 0; i < chats.length; i += 2) {
								if (!chats[i] && !chats[i + 1]) {
									continue;
								}
								let coldChat = chats[i];
								let hotChat = chats[i + 1];
								// 冷热消息合并
								let chat = Object.assign({}, coldChat, hotChat);
								if (hotChat && coldChat) {
									chat.messages = coldChat.messages.concat(hotChat.messages)
								}
								chatsData.chats.push(chat);
							}
							this.initChats(chatsData);
							resolve();
						})
					}
				}).catch(e => {
					console.log("加载消息失败")
					reject(e);
				})
			})
		},

		/**
		 * 对会话列表进行排序，最新消息的会话排在最前面
		 */
		sortChats() {
			if (this.chats && this.chats.length > 0) {
				this.chats.sort((a, b) => {
					const timeA = a.lastSendTime ? new Date(a.lastSendTime).getTime() : 0;
					const timeB = b.lastSendTime ? new Date(b.lastSendTime).getTime() : 0;
					return timeB - timeA; // 降序排列，最新的在前面
				});
			}
		},

		/**
		 * 从AI消息内容中提取用于会话列表显示的回复内容
		 * @param {string} content - AI消息内容
		 * @param {object} chat - 聊天对象，用于区分私聊和群聊
		 */
		extractAIResponseForChat(content, chat = null) {
			// 确保content是字符串类型
			if (!content) return '';
			const contentStr = typeof content === 'string' ? content : String(content);

			let atUserName = '';
			let processedContent = contentStr;

			// 只有群聊才显示@用户名，私聊不显示
			if (chat && chat.type === 'GROUP' && contentStr.startsWith('@')) {
				const firstNewlineIndex = contentStr.indexOf('\n');
				if (firstNewlineIndex !== -1) {
					atUserName = contentStr.substring(0, firstNewlineIndex).trim() + ' ';
					processedContent = this.removeAtUserPrefix(contentStr);
				}
			} else if (contentStr.startsWith('@')) {
				// 私聊情况下，移除@用户名前缀，不在会话列表中显示
				processedContent = this.removeAtUserPrefix(contentStr);
			}

			// 如果包含完整的AI消息格式，提取回复部分
			if (processedContent.includes('🤖 *回复*')) {
				const responseMarker = '🤖 *回复*';
				const responseIndex = processedContent.indexOf(responseMarker);
				if (responseIndex !== -1) {
					let responseContent = processedContent.substring(responseIndex + responseMarker.length).trim();
					// 限制长度，避免会话列表显示过长（考虑@用户名的长度）
					const maxLength = 50 - atUserName.length;
					if (responseContent.length > maxLength) {
						responseContent = responseContent.substring(0, maxLength) + '...';
					}
					return atUserName + responseContent;
				}
			}

			// 如果是简单的回复内容，直接返回（限制长度）
			const maxLength = 50 - atUserName.length;
			if (processedContent.length > maxLength) {
				return atUserName + processedContent.substring(0, maxLength) + '...';
			}

			return atUserName + processedContent;
		},

		/**
		 * 移除群聊AI消息开头的@用户名部分
		 */
		removeAtUserPrefix(content) {
			if (!content) return ''
			// 确保content是字符串类型
			const contentStr = typeof content === 'string' ? content : String(content);

			// 检查是否以@开头（群聊AI回复格式）
			if (contentStr.startsWith('@')) {
				// 查找第一个换行符，移除@用户名部分
				const firstNewlineIndex = contentStr.indexOf('\n')
				if (firstNewlineIndex !== -1) {
					// 移除@用户名和后面的空行，保留实际内容
					let remainingContent = contentStr.substring(firstNewlineIndex + 1)
					// 移除开头的空行
					while (remainingContent.startsWith('\n')) {
						remainingContent = remainingContent.substring(1)
					}
					return remainingContent
				}
			}

			// 如果不是群聊格式，直接返回原内容
			return contentStr
		}
	},
	getters: {
		isLoading: (state) => () => {
			return state.loadingPrivateMsg || state.loadingGroupMsg
		},
		findChats: (state) => () => {
			if (cacheChats && state.isLoading()) {
				return cacheChats;
			}
			return state.chats;
		},
		findChatIdx: (state) => (chat) => {
			let chats = state.findChats();
			for (let idx in chats) {
				if (chats[idx].type == chat.type &&
					chats[idx].targetId === chat.targetId) {
					chat = chats[idx];
					return idx
				}
			}
		},
		findChat: (state) => (chat) => {
			let chats = state.findChats();
			let idx = state.findChatIdx(chat);
			return chats[idx];
		},
		findChatByFriend: (state) => (fid) => {
			let chats = state.findChats();
			return chats.find(chat => chat.type == 'PRIVATE' &&
				chat.targetId == fid)
		},
		findChatByGroup: (state) => (gid) => {
			let chats = state.findChats();
			return chats.find(chat => chat.type == 'GROUP' &&
				chat.targetId == gid)
		},
		findMessage: (state) => (chat, msgInfo) => {
			if (!chat) {
				return null;
			}
			for (let idx in chat.messages) {
				const existingMsg = chat.messages[idx];

				// 1. 通过id判断（最准确的匹配方式）
				if (msgInfo.id && existingMsg.id == msgInfo.id) {
					return existingMsg;
				}

				// 2. 正在发送中的消息可能没有id,只有tmpId
				if (msgInfo.tmpId && existingMsg.tmpId &&
					existingMsg.tmpId == msgInfo.tmpId) {
					return existingMsg;
				}
			}
			return null;
		}
	}
});